
#include <jni.h>
#include <android/log.h>

#include "ctcpdownload.h"
#include "ctcpupload.h"
#include "cspeexencoder.h"
#include "cspeexdecoder.h"
#include "com_iwthings_speex_SpeexJni.h"

struct SPEEX_CTX
{
    CSpeexEncoder *encoder;
    CSpeexDecoder *decoder;
    CTcpUpload   *upload ;
    CTcpDownload *download;

    bool  bdownload;
    jclass     c;
    jmethodID  method;
    JNIEnv    *env;
};

SPEEX_CTX g_speex;
const char *strCAudioPlayer = "com/iwthings/speex/SpeexPlayer";
const char *strMPlayAudio = "PlayAudio";
const char *strTypePlayAudio = "([SI)V";

short g_speexbuf[160];
//aac 从服务器下载后回调


int FindMethodPlayAudio()
{

    g_speex.c = g_speex.env->FindClass(strCAudioPlayer);
    if( g_speex.c == NULL)
    {
        __android_log_print(ANDROID_LOG_INFO, "SPEEX", "FindClass error" );
        return -1;
    }
    g_speex.method = g_speex.env->GetStaticMethodID(g_speex.c, strMPlayAudio,strTypePlayAudio);
    if (g_speex.method == NULL)
    {
        __android_log_print(ANDROID_LOG_INFO, "SPEEX", "GetMethodID error" );
        return -1;
    }
    return 0;
}
void cb_speex_download(char *data, int len)
{
    if(g_speex.method == NULL)
    {
        if(FindMethodPlayAudio()<0)
        {
            return ;
        }
    }

    //__android_log_print(ANDROID_LOG_INFO, "SPEEX", "cb_speex_download:%d",len );
    if(g_speex.decoder != NULL)
    {

        int size = g_speex.decoder->Decoder(data, len, g_speexbuf);
        //__android_log_print(ANDROID_LOG_INFO, "SPEEX", "Speex decode:%d",size );
        if(size == 0)
        {
            jshortArray var = NULL;
            var = g_speex.env->NewShortArray(160);
            g_speex.env->SetShortArrayRegion(var,0,160,g_speexbuf);
            g_speex.env->CallStaticVoidMethod( g_speex.c, g_speex.method,var,160);
            if(var != NULL)
            {
                g_speex.env->DeleteLocalRef(var);
                var = NULL;
            }
        }
    }
}


JNIEXPORT jint JNICALL Java_com_iwthings_speex_SpeexJni_OpenSpeexEncoder
(JNIEnv *env, jobject obj, jint userid, jstring ip, jint port)
{

    int iret = 0;
    const char* strIP;
    strIP = env->GetStringUTFChars(ip, 0);

    //open encoder
    g_speex.encoder = new CSpeexEncoder;
    if(g_speex.encoder == NULL)
    {
        return -1;
    }
    iret = g_speex.encoder->InitSpeex();
    if(iret < 0)
    {
        __android_log_print(ANDROID_LOG_INFO, "SPEEX", "error" );
        return -1;
    }
    //open upload
    g_speex.upload = new CTcpUpload;
    iret = g_speex.upload->OpenUpload(userid,strIP,port);
    if(iret < 0)
    {
        __android_log_print(ANDROID_LOG_INFO, "SPEEX", "SPEEX OpenUpload error ip: %s  port:%d" ,strIP,port);
        delete g_speex.upload;
        g_speex.upload = NULL;
        return -1;
    }
    env->ReleaseStringUTFChars(ip, strIP);
    __android_log_print(ANDROID_LOG_INFO, "SPEEX", "OpenSpeexEncoder" );

    return 0;
}

JNIEXPORT jint JNICALL Java_com_iwthings_speex_SpeexJni_CloseSpeexEncoder
(JNIEnv *env, jobject obj)
{
    //close encoder
    if(g_speex.encoder != NULL)
    {
        g_speex.encoder->UninitSpeex();
        delete g_speex.encoder;
        g_speex.encoder = NULL;
    }
    //close upload
    if(g_speex.upload != NULL)
    {
        g_speex.upload->CloseUpload();
        delete g_speex.upload;
        g_speex.upload = NULL;
    }

    return 0;
}

JNIEXPORT jint JNICALL Java_com_iwthings_speex_SpeexJni_SpeexEncode
 (JNIEnv *env, jobject obj, jshortArray record, jshortArray play)
{
    if(g_speex.encoder == NULL || record == NULL)
    {
        return -1;
    }
    char buf[128] ;
    short *sRecord = NULL;
    short *sPlay = NULL;


    sRecord = (short*)env->GetShortArrayElements(record, 0);
    if(play != NULL)
    {
        sPlay = (short*)env->GetShortArrayElements(play, 0);
    }


    int iRet = g_speex.encoder->Encode(sRecord,sPlay,buf);
    if(iRet > 0)
    {
        __android_log_print(ANDROID_LOG_INFO, "SPEEX", "Speex encode:%d",iRet );
        g_speex.upload->Upload((char *)buf, iRet);
    }

    env->ReleaseShortArrayElements ( record, sRecord,   0);
    env->ReleaseShortArrayElements ( play, sPlay,   0);

    return 0;
}


JNIEXPORT jint JNICALL Java_com_iwthings_speex_SpeexJni_OpenSpeexDecoder
(JNIEnv *env, jobject obj, jint userid, jstring ip , jint port)
{


    int iret = 0;
    const char* strIP;
    strIP = env->GetStringUTFChars(ip, 0);

    //open download
    g_speex.download = new CTcpDownload;
    g_speex.bdownload = false;

    iret = g_speex.download->OpenDownload(userid,&cb_speex_download,strIP,port);
    if(iret < 0)
    {
        __android_log_print(ANDROID_LOG_INFO, "SPEEX", "SPEEX OpenDownload error ip: %s  port:%d" ,strIP,port);
        delete g_speex.download;
        g_speex.download = NULL;
        return -1;
    }

    g_speex.decoder = new CSpeexDecoder;
    iret = g_speex.decoder->InitSpeex();
    if(iret < 0)
    {
        delete g_speex.decoder;
        g_speex.decoder = NULL;
        return -1;
    }

    __android_log_print(ANDROID_LOG_INFO, "SPEEX", "OpenSPEEXDecoder" );

    env->ReleaseStringUTFChars(ip, strIP);

    return 0;
}


JNIEXPORT jint JNICALL Java_com_iwthings_speex_SpeexJni_CloseSpeexDecoder
(JNIEnv *env, jobject obj)
{
    if(g_speex.download != NULL)
    {
        g_speex.download->CloseDownload();
        while(g_speex.bdownload)
        {
            usleep(100);
        }
        delete g_speex.download;
        g_speex.download = NULL;
    }


    if(g_speex.decoder != NULL)
    {
        g_speex.decoder->UninitSpeex();
        delete g_speex.decoder;
        g_speex.decoder = NULL;
    }
    return 0;
}


JNIEXPORT jint JNICALL Java_com_iwthings_speex_SpeexJni_SpeexDecoder
(JNIEnv *env, jobject obj)
{
    g_speex.env = env;
    if(g_speex.download != NULL)
    {
        g_speex.bdownload = true;
        g_speex.download->Download();
        g_speex.bdownload = false;
    }
    return 0;
}
